﻿#ifndef JZNODE_H_
#define JZNODE_H_

#include <QSharedPointer>
#include <QDataStream>
#include "JZNodePin.h"
#include "JZNodeIR.h"
#include "JZNodeFunctionDefine.h"

enum
{
    Node_none,    
    Node_unknown,
    Node_nop,
    Node_param,
    Node_create,
    Node_createFromString,
    Node_this,
    Node_setParam,
    Node_memberParam,
    Node_setMemberParam,
    Node_literal,
    Node_enum,
    Node_flag,
    Node_convert,
    Node_functionPointer,
    Node_functionStart,
    Node_function,      
    Node_genericFunction,
    Node_clone,
    Node_assert,
    Node_swap,

    Node_add,
    Node_sub,
    Node_mul,
    Node_div,
    Node_mod,    
    Node_eq,  // ==
    Node_ne,  // !=
    Node_le,  // <=
    Node_ge,  // >=
    Node_lt,  // <
    Node_gt,  // >
    Node_bitand,
    Node_bitor,    
    Node_bitxor,
    Node_and,
    Node_or,
    Node_bitreverse,
    Node_not,
    Node_neg,
    Node_expr,
    Node_for,
    Node_foreach,
    Node_while,    
    Node_sequence,
    Node_if,                
    Node_parallel,
    Node_format,
    Node_formatBin,
    Node_print,
    Node_log,
    Node_display,
    Node_switch,
    Node_break,
    Node_continue,
    Node_return,
    Node_tryCatch,
    Node_throw,   
    Node_signalConnect,
    Node_mainLoop,
    Node_unitTest,

    Node_showEvent,
    Node_closeEvent,
    Node_resizeEvent,
    Node_paintEvent,

    Node_mousePressEvent,
    Node_mouseMoveEvent,
    Node_mouseReleaseEvent,
    
    Node_keyPressEvent,
    Node_keyReleaseEvent,

    Node_buttonClickedEvent,
    Node_timerEvent,

    Node_custom = 0x1000,
};

enum
{
    NodeProp_none = 0,
    NodeProp_noRemove = 0x1,
};

#define MAX_PIN_ID 100

//JZNodeGemo
struct JZNodeGemo
{
    static int paramId(int nodeId, int pinId);
    static JZNodeGemo fromParamId(int param_id);

    JZNodeGemo();
    JZNodeGemo(int id, int pin_id);

    int paramId() const;
    bool isNull() const;
    bool operator==(const JZNodeGemo &other) const;
    bool operator!=(const JZNodeGemo &other) const;

    int nodeId;
    int pinId;
};
void operator<<(QDataStream& s, const JZNodeGemo& param);
void operator>>(QDataStream& s, JZNodeGemo& param);

//JZNodeConnect
class JZNodeConnect
{
public:
    JZNodeConnect();
    
    int id;
    JZNodeGemo from;
    JZNodeGemo to;
};
void operator<<(QDataStream &s, const JZNodeConnect &param);
void operator>>(QDataStream &s, JZNodeConnect &param);

//JZNodeGroup
class JZNodeGroup
{
public:
    JZNodeGroup();

    int id;
    QString memo;
};
void operator<<(QDataStream &s, const JZNodeGroup &param);
void operator>>(QDataStream &s, JZNodeGroup &param);

class JZScriptEnvironment;
class JZNodeCompiler;
class JZScriptItem;
class JZNodePinWidget;
class JZNode
{
public:
    JZNode();
    virtual ~JZNode();

    QByteArray toBuffer();
    bool fromBuffer(const QByteArray &object);

    JZScriptItem *file() const;
    void setFile(JZScriptItem *file);
    QString path();

    const JZScriptEnvironment *environment() const;

    const QString &name() const;
    QString uniqueName() const;

    int id() const;
    void setId(int id);
    int type() const;

    QPointF pos() const;
    void setPos(QPointF pos);

    void setFlag(int flag);
    int flag() const;

    void setGroup(int group);
    int group();

    const QString &memo() const;
    void setMemo(const QString &text);

    bool isFlowNode() const;
    bool isParamNode() const;

    int addPin(const JZNodePin &pin);         
    void removePin(int id);
    void clearPin();
    JZNodePin *pin(int id);
    const JZNodePin *pin(int id) const;
    JZNodePin* pinByIndex(int index);
    const JZNodePin* pinByIndex(int index) const;
    JZNodePin *pin(QString name);
    bool hasPin(int id) const;
    int indexOfPin(int id) const;
    int indexOfPinByName(QString name) const;
    int indexOfPinByType(int id, int type) const;
    QList<int> pinInList(int flag = 0) const;
    QList<int> pinOutList(int flag = 0) const;
    QList<int> pinListByType(int flag) const;
    QList<int> pinList() const;
    int pinCount() const;
    int pinCount(int flag) const;
              
    int addParamIn(QString name,int extFlag = 0);    
    int paramIn(int index) const;    
    JZNodeGemo paramInGemo(int index) const;
    int paramInId(int index) const;
    int paramInCount() const;
    QList<int> paramInList() const;
    QString paramInValue(int index) const;
    void setParamInValue(int index, const QString &value);

    int addParamOut(QString name,int extFlag = 0);
    int paramOut(int index) const;
    JZNodeGemo paramOutGemo(int index) const;
    int paramOutId(int index) const;
    int paramOutCount() const;
    QList<int> paramOutList() const;
    QString paramOutValue(int index) const;
    void setParamOutValue(int index, const QString &value);
    
    int addFlowIn(int extFlag = 0);
    int flowIn() const;
    JZNodeGemo flowInGemo() const;
    int flowInCount() const;

    int addFlowOut(QString name = QString(),int extFlag = 0);
    int flowOut(int index = 0) const;
    JZNodeGemo flowOutGemo(int index = 0) const;
    QList<int> flowOutList() const;
    int flowOutCount() const;

    int addSubFlowOut(QString name,int extFlag = 0);
    int subFlowOut(int index) const;
    JZNodeGemo subFlowOutGemo(int index) const;
    QList<int> subFlowList() const;
    int subFlowCount() const;
    
    const QString &pinValue(int pin) const;
    void setPinValue(int pin, const QString &value);
    const QString &pinName(int id) const;
    void setPinName(int id,const QString &name);

    bool canRemove(); 
    virtual bool canLink(int node_id, int pin_id, QString &error);

    const QStringList &pinType(int id) const;    
    virtual bool compiler(JZNodeCompiler *compiler,QString &error) = 0; 
    void update();
    virtual bool updateNode(QString &error);      //更新
    
protected:     
    Q_DISABLE_COPY(JZNode)

    friend JZScriptItem;
    virtual void saveToStream(QDataStream &s) const;
    virtual void loadFromStream(QDataStream &s);

    void paramInResize(int size);
    void paramOutResize(int size);

    virtual void onPinLinked(int pin_id);
    virtual void onPinUnlinked(int pin_id);
    virtual void onPinChanged(int pin_id);
    
    void setPinTypeArg(int id);
    void setPinTypeInt(int id);
    void setPinTypeNumber(int id);
    void setPinTypeBool(int id);
    void setPinTypeString(int id);
    void setPinType(int id,const QStringList &type);
    void clearPinType(int id);

    int m_id;
    int m_type;
    int m_flag;
    int m_group;
    QString m_name;
    QPointF m_pos;
    QString m_memo;
    QList<JZNodePin> m_pinList;
    JZScriptItem *m_file;
};

class JZNodeUnknown : public JZNode
{
public:
    JZNodeUnknown();
    virtual ~JZNodeUnknown();

    virtual bool compiler(JZNodeCompiler* compiler, QString& error);
};

#endif
